﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;

using Ninject;

using SSTU.Contract.Common;
using SSTU.Contract.Facade;
using SSTU.Contract.Interaction;
using SSTU.Management.Dependency;
using SSTU.Model;
using SSTU.ViewModel.Core;
using SSTU.ViewModel.Item;
using System.Globalization;

namespace SSTU.ViewModel
{
	/// <summary>
	/// View model for main menu with time tables, faculty/group selecting.
	/// </summary>
	public class TimeTableMenuViewModel : AppViewModelBase
	{
		private readonly IStructureFacade _structureFacade;
		private readonly INavigationInteraction _navigationInteraction;

		/// <summary>
		/// Initializes a new instance of the <see cref="TimeTableMenuViewModel"/> class.
		/// </summary>
		/// <param name="structureFacade">The structure facade.</param>
		/// <param name="navigationInteraction">The navigation interaction.</param>
		[Inject]
		public TimeTableMenuViewModel(
			IStructureFacade structureFacade,
			INavigationInteraction navigationInteraction)
		{
			DependencyRequirement.Current.NotNullFromConstructorInjection<TimeTableMenuViewModel, IStructureFacade>(structureFacade);
			DependencyRequirement.Current.NotNullFromConstructorInjection<FacultyMenuViewModel, INavigationInteraction>(navigationInteraction);
			_structureFacade = structureFacade;
			_navigationInteraction = navigationInteraction;
			Faculties = new ObservableCollection<FacultyItemVM>();
			FavoriteGroups = new ObservableCollection<GroupItemVM>();
			FavoriteCommand = new DelegateCommand<GroupItemVM>(ExecuteFavoriteCommand, CanExecuteFavoriteCommand);
		}

		public void Initialize()
		{
			IsFacultiesFromServerLoaded = false;
			IsFavoriteGroupsFromLocalLoaded = false;
			UpdateIsBusy();
			_structureFacade.LoadFacultiesAsync(OnFacultiesLoaded);
			_structureFacade.LoadFavoriteGroupsAsync(OnFavoriteGroupsLoaded);
		}

		/// <summary>
		/// Gets observable collection of the available faculties.
		/// </summary>
		public ObservableCollection<FacultyItemVM> Faculties { get; private set; }

		/// <summary>
		/// Gets observable collection of the available groups from the favorite-list.
		/// </summary>
		public ObservableCollection<GroupItemVM> FavoriteGroups { get; private set; }

		/// <summary>
		/// Gets command for changing 'FavoriteState' of the group from favorite-list.
		/// </summary>
		public DelegateCommand<GroupItemVM> FavoriteCommand { get; private set; }

		/// <summary>
		/// Gets a value indicating whether in this instance faculties from server is loaded.
		/// </summary>
		public bool IsFacultiesFromServerLoaded { get; private set; }

		/// <summary>
		/// Gets a value indicating whether in this instance favorite groups from local is loaded.
		/// </summary>
		public bool IsFavoriteGroupsFromLocalLoaded { get; private set; }

		/// <summary>
		/// Called when faculties loaded.
		/// </summary>
		/// <param name="response">The facade response.</param>
		private void OnFacultiesLoaded(FacadeResponse<IEnumerable<Faculty>> response)
		{
			// Faculties from server can be loaded before than faculties from local.
			if (!IsFacultiesFromServerLoaded)
			{
				if (response.DataSource == FacadeResponseDataSource.Server)
				{
					IsFacultiesFromServerLoaded = true;
				}
				bool isSuccess = (response.IsSuccess && (response.Data != null));
				if (isSuccess)
				{
					Faculties.Clear();
					foreach (var faculty in response.Data.OrderBy(i => i.ShortName))
					{
						var departmentItem = new FacultyItemVM(faculty.Id, faculty.ShortName, faculty.LongName);
						Faculties.Add(departmentItem);
					}
				}
				else
				{
					DisplayError(response.DataSource, "списка факультетов", response.Error);
				}
				UpdateIsBusy();
			}
		}

		/// <summary>
		/// Called when favorite groups loaded.
		/// </summary>
		/// <param name="response">The facade response.</param>
		private void OnFavoriteGroupsLoaded(FacadeResponse<IEnumerable<Group>> response)
		{
			IsFavoriteGroupsFromLocalLoaded = true;
			UpdateIsBusy();
			bool isSuccess = (response.IsSuccess && (response.Data != null));
			if (isSuccess)
			{
				FavoriteGroups.Clear();
				foreach (var group in response.Data.OrderBy(g => g.ShortName))
				{
					var favoriteState = group.IsFavorite ? FavoriteState.Favorite : FavoriteState.NotFavorite;
					var groupItem = new GroupItemVM(group.Id, group.ShortName, group.LongName, favoriteState);
					FavoriteGroups.Add(groupItem);
				}
			}
			else
			{
				DisplayError(response.DataSource, "избранных групп", response.Error);
			}
		}

		/// <summary>
		/// Updates the is busy status.
		/// </summary>
		private void UpdateIsBusy()
		{
			IsBusy = !IsFacultiesFromServerLoaded || !IsFavoriteGroupsFromLocalLoaded;
		}

		/// <summary>
		/// Opens the faculty item, navigates to the page with faculty menu.
		/// </summary>
		/// <param name="departmentItem">The department item.</param>
		public void OpenFaculty(FacultyItemVM departmentItem)
		{
			_navigationInteraction.ToFacultyMenu(departmentItem);
		}

		/// <summary>
		/// Opens the group item, navigates to the page with group menu.
		/// </summary>
		/// <param name="groupItem">The group item.</param>
		public void OpenGroup(GroupItemVM groupItem)
		{
			_navigationInteraction.ToGroupTimeTable(groupItem);
		}

		/// <summary>
		/// Executes the favorite command, change the 'FavoriteState' of the group item.
		/// </summary>
		/// <param name="groupItem">The group item.</param>
		private void ExecuteFavoriteCommand(GroupItemVM groupItem)
		{
			groupItem.FavoriteState = FavoriteState.ChangingToNotFavorite;
			FavoriteCommand.RaiseCanExecuteChanged();
			_structureFacade.RemoveGroupFromFavoritesAsync(groupItem.Id, response =>
			{
				groupItem.FavoriteState = response.IsSuccess ? FavoriteState.NotFavorite : FavoriteState.Favorite;
				if (groupItem.FavoriteState == FavoriteState.NotFavorite)
				{
					FavoriteGroups.Remove(groupItem);
				}
				FavoriteCommand.RaiseCanExecuteChanged();
			});
		}

		/// <summary>
		/// Determines whether this instance can execute favorite command, for the specified group item.
		/// </summary>
		/// <param name="groupItem">The group item.</param>
		private bool CanExecuteFavoriteCommand(GroupItemVM groupItem)
		{
			bool result =
				groupItem != null &&
				!string.IsNullOrEmpty(groupItem.Id) &&
				groupItem.FavoriteState == FavoriteState.Favorite;
			return result;
		}
	}
}
